#include "HelloWorldScene.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"
#include "AStar.hpp"
#include <fstream>

USING_NS_CC;
using namespace cocos2d::ui;
using namespace cocostudio::timeline;

//using namespace AStarWithNoWeight1;
//using namespace AStarWithNoWeight2;
//using namespace AStarWithWeight;
//using namespace bfs;
using namespace dfs;

Scene* HelloWorld::createScene()
{
    auto scene = Scene::create();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}

bool HelloWorld::init()
{
	this->state = NONE;
	this->initUI();
	this->initDrawNode();

    return true;
}

void HelloWorld::initUI()
{
    auto rootNode = CSLoader::createNode("MainScene.csb");
    this->addChild(rootNode);

	auto btnStart = (Button*)rootNode->getChildByName("btn_start");
	auto btnEnd = (Button*)rootNode->getChildByName("btn_end");
	auto btnGo = (Button*)rootNode->getChildByName("btn_go");
	auto btnBarrier = (Button*)rootNode->getChildByName("btn_barrier");
	auto btnOpen = (Button*)rootNode->getChildByName("btn_open");
	auto btnSave = (Button*)rootNode->getChildByName("btn_save");

	btnStart->addClickEventListener([this](Ref* pRef){
		this->state = SET_START_POINT;
	});
	btnEnd->addClickEventListener([this](Ref *pRef){
		this->state = SET_END_POINT;
	});
	btnBarrier->addClickEventListener([this](Ref* pRef){
		this->state = SET_BARRIER;
	});
	btnGo->addClickEventListener([this](Ref* pRef){
		this->state = NONE;
		this->astarSearch();
	});

	btnSave->addClickEventListener([this](Ref* pRef) {
		std::ofstream file;
		file.open("map.txt");
		if (file.is_open())
		{
			file << model.getHType() << endl;
			file << model.getStartX() << " " << model.getStartY() << endl;
			file << model.getEndX() << " " << model.getEndY() << endl;
			int list[MAP_BLOCK_COUNT * MAP_BLOCK_COUNT], n;
			model.getBarriers(list, n);
			for (int i = 0; i < n; i++)
			{
				file << list[i] << " ";
			}
		}
		file.close();
	});

	btnOpen->addClickEventListener([this](Ref* pRef) {
		std::ifstream file;
		file.open("map.txt");
		if (file.is_open())
		{
			int x, y;
			model.clear();
			file >> x;
			model.setHType(x);
			file >> x >> y;
			model.setStartPoint(x, y);
			file >> x >> y;
			model.setEndPoint(x, y);
			while (!file.eof())
			{
				file >> x >> y;
				model.setBarrier(x, y);
			}
			this->drawMap();
		}
		file.close();
	});

	this->drawPanel = (Layout*)rootNode->getChildByName("pnl_draw");
	this->drawPanel->setTouchEnabled(false);
	auto listener = EventListenerTouchOneByOne::create();
	listener->onTouchBegan = [this](Touch *t, Event *e) {return true; };
	listener->onTouchEnded = [this](Touch *t, Event *e)
	{
		auto pos = t->getLocation();
		this->onTouchPanel(pos);
	};
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
}

void HelloWorld::initDrawNode()
{
	this->drawNode = DrawNode::create();
	this->drawPanel->addChild(this->drawNode);
	this->drawMap();
}

void HelloWorld::drawMap()
{
	this->drawNode->clear();
	for (int i = 0; i < MAP_BLOCK_COUNT; i++)
	{
		for (int j = 0; j < MAP_BLOCK_COUNT; j++)
		{
			Color4F color;
			switch (this->model.getBlockType(i, j))
			{
			case START_POINT:
			{
				color = Color4F(1.0f, 0, 0, 1.0f);
				break;
			}
			case END_POINT:
			{
				color = Color4F(0.8f, 0.8f, 0, 1.0f);
				break;
			}
			case SPACE:
			case VISITING:
			{
				color = Color4F(0.8f, 0.8f, 0.8f, 1.0f);
				break;
			}
			case BARRIER:
			{
				color = Color4F(0.2f, 0.2f, 0.2f, 1.0f);
				break;
			}
			case VISITED:
			{
				color = Color4F(0, 1.0f, 0, 1.0f);
				break;
			}
			case ON_PATH:
			{
				color = Color4F(0, 0, 1.0f, 1.0f);
				break;
			}
			default:
				color = Color4F(model.getBlockType(i, j) / 255.0, 0, 0, 1.0f);
				break;
			}
			this->drawNode->drawSolidRect(Vec2(i * MAP_BLOCK_SZIE, j * MAP_BLOCK_SZIE), Vec2((i + 1) * MAP_BLOCK_SZIE, (j + 1) * MAP_BLOCK_SZIE), color);
			this->drawNode->drawRect(Vec2(i * MAP_BLOCK_SZIE, j * MAP_BLOCK_SZIE), Vec2((i + 1) * MAP_BLOCK_SZIE, (j + 1) * MAP_BLOCK_SZIE), Color4F(1.0f, 1.0f, 0, 1.0f));
		}
	}
}

void HelloWorld::onTouchPanel(Vec2 pos)
{
	if (this->state == NONE)
	{
		return;
	}
	pos = this->drawPanel->convertToNodeSpace(pos);
	if (pos.x < 0 || pos.x > MAP_BLOCK_SZIE * MAP_BLOCK_COUNT || pos.y < 0 || pos.y > MAP_BLOCK_SZIE * MAP_BLOCK_COUNT)
	{
		return;
	}
	int x = floor(pos.x / MAP_BLOCK_SZIE);
	int y = floor(pos.y / MAP_BLOCK_SZIE);
	switch (this->state)
	{
	case SET_START_POINT:
	{
		this->model.setStartPoint(x, y);
		break;
	}
	case SET_END_POINT:
	{
		this->model.setEndPoint(x, y);
		break;
	}
	case SET_BARRIER:
	{
		if (model.getBlockType(x, y) == BARRIER)
		{
			this->model.setSpace(x, y);
		}
		else
		{
			this->model.setBarrier(x, y);
		}
	}
	default:
		break;
	}
	this->drawMap();
}

void HelloWorld::astarSearch()
{
	if (!model.check())
	{
		log("start point or end point invalid!");
		return;
	}

	this->model.reset();
	auto len = search(this->model);

	log("%f", len);
	this->drawMap();
}
